import { REG_TIME_MOMENT, REG_DATE_MOMENT, setMomentToSameDay } from "./dateUtil";
import Worker from "./Worker";
import moment, { Moment } from 'moment';
import AttendanceRecord, { ClockInfo, ClockInInfo, ClockInResult, ClockOutInfo, ClockOutResult } from "./AttendanceRecord";
import { UploadFile } from "antd/lib/upload/interface";
import { v4 as uuid } from 'uuid';
import { parseFileToSheetJson } from "./fileToModelUtil";
import { addAttendanceRecordItemModel, addUndefinedWorker, getWorker, refreshIsValidStatus, setEndDate, setStartDate } from "./store";
import UndefinedWorker from "./UndefinededWorker";
import { getMachineIdByFilename } from "./machineHandler";

export interface ModelInfo {
    model: Map<Worker, AttendanceRecord[]>;
    startDate: Moment | null;
    endDate: Moment | null;
    isValid: boolean;
    undefinedWorkerList: UndefinedWorker[];
}

export function parseClockInfoToMomentList(date: Moment, clockInfo: string): Moment[] {
    const momentList: Moment[] = [];
    const limit = clockInfo.length;
    let i = 0;
    while (i < limit) {
        let tempTimeStr = clockInfo.substring(i, i += 5);
        if (REG_TIME_MOMENT.test(tempTimeStr)) {
            const clockMoment = moment(tempTimeStr, 'HH:mm:ss');
            setMomentToSameDay(clockMoment, date);
            momentList.push(clockMoment);
        }
    }

    return momentList.sort((a, b) => {
        return a.isBefore(b) ? -1 : 1;
    });
}

export function calculateClockInfo(date: Moment, clockMomentList: Moment[], worker: Worker): ClockInfo {
    const { clockInMoment, clockOutMoment, beLateMoment, absenteeismLateMoment, absenteeismEarlyMoment } = worker.department;
    setMomentToSameDay(clockInMoment, date);
    setMomentToSameDay(clockOutMoment, date);
    setMomentToSameDay(beLateMoment, date);
    setMomentToSameDay(absenteeismLateMoment, date);
    setMomentToSameDay(absenteeismEarlyMoment, date);
    const clockTimes = clockMomentList.length;
    let clockInInfo: ClockInInfo;
    let clockOutInfo: ClockOutInfo;
    if (clockTimes > 0) {
        const firstClockMoment = clockMomentList[0];
        const lastClockMoment = clockMomentList[clockTimes - 1];
        if (firstClockMoment.isSameOrBefore(clockInMoment)) {
            clockInInfo = new ClockInInfo(firstClockMoment, ClockInResult.NORMAL);
        } else if (firstClockMoment.isSameOrBefore(beLateMoment)) {
            clockInInfo = new ClockInInfo(firstClockMoment, ClockInResult.BE_LATE);
        } else if (firstClockMoment.isSameOrBefore(absenteeismLateMoment)) {
            clockInInfo = new ClockInInfo(firstClockMoment, ClockInResult.TOO_LATE);
        } else {
            clockInInfo = new ClockInInfo(null, ClockInResult.ABSENTEEISM_LATE);
        }

        if (lastClockMoment.isSameOrAfter(clockOutMoment)) {
            clockOutInfo = new ClockOutInfo(lastClockMoment, ClockOutResult.NORMAL);
        } else if (lastClockMoment.isSameOrAfter(absenteeismEarlyMoment)) {
            clockOutInfo = new ClockOutInfo(lastClockMoment, ClockOutResult.EARLY);
        } else {
            clockOutInfo = new ClockOutInfo(null, ClockOutResult.ABSENTEEISM_EARLY);
        }
    } else {
        clockInInfo = new ClockInInfo(null, ClockInResult.ABSENTEEISM_LATE);
        clockOutInfo = new ClockOutInfo(null, ClockOutResult.ABSENTEEISM_EARLY);
    }
    return new ClockInfo(clockInInfo, clockOutInfo);
}

export function parseAttendanceRecordByFile(file: UploadFile): Promise<void> {
    return new Promise((resolve, reject) => {
        const fileName = file.name;
        const sheetName = '考勤记录';
        const machineId = getMachineIdByFilename(fileName);
        if (machineId !== null && file.originFileObj !== undefined) {
            parseFileToSheetJson(file, sheetName).then(attendanceJson => {
                const startDateAndEndDate = attendanceJson[2][2];
                let startDate: Moment | null = null,
                    endDate: Moment | null = null,
                    validDays: number = 0;
                const [startDateStr, endDateStr] = startDateAndEndDate.split("~");
                if (REG_DATE_MOMENT.test(startDateStr) && REG_DATE_MOMENT.test(endDateStr)) {
                    startDate = moment(startDateStr.trim());
                    endDate = moment(endDateStr.trim());
                    if (startDate.isAfter(endDate)) {
                        const temp = startDate;
                        startDate = endDate;
                        endDate = temp;
                    }
                    setStartDate(startDate);
                    setEndDate(endDate);
                    validDays = endDate.diff(startDate, 'd') + 1;
                    let i = 4, limit = attendanceJson.length;
                    while (i < limit) {
                        const info = attendanceJson[i++];
                        const id = info[2];
                        const name = info[10];
                        if (id.length > 0 && name.length > 0) {
                            const worker = getWorker(machineId, id);
                            if (worker === undefined) {
                                const department = info[20];
                                addUndefinedWorker(new UndefinedWorker({
                                    workBook: fileName,
                                    sheet: sheetName,
                                    id,
                                    name,
                                    department
                                }));
                            } else {
                                const attendanceRecordOriginInfoList = attendanceJson[i];
                                const attendanceRecordList = new Array<AttendanceRecord>(validDays);
                                for (let j = 0, limit = Math.min(validDays, attendanceRecordOriginInfoList.length); j < limit; j++) {
                                    const date = startDate.clone().add(j, 'd');
                                    const origin = attendanceRecordOriginInfoList[j];
                                    const clockMomentList = parseClockInfoToMomentList(date, origin);
                                    const clockInfo = calculateClockInfo(date, clockMomentList, worker);
                                    const attendanceRecord = new AttendanceRecord({
                                        id: uuid(),
                                        worker,
                                        date,
                                        origin,
                                        clockInfo,
                                        clockMomentList
                                    });
                                    attendanceRecordList[j] = attendanceRecord;
                                }
                                addAttendanceRecordItemModel({ worker, attendanceRecordList });
                            }
                        }
                        i++;
                    }
                    resolve();
                } else {
                    reject(`文件《${fileName}》中，《${sheetName}》日期范围无效，请检查考勤记录表数据和格式是否正确。`);
                }
            });
        } else if (machineId === null) {
            reject(`文件名 《${fileName}》中未查找到有效的考勤机编号信息，请检查文件名是否包含正确的考勤机编号。`);
        } else {
            reject(`《${fileName}》是无效的考勤记录文件，请严格按照格式要求上传数据和格式正确的文件。`);
        }
    });
}

export function parseAttendanceRecordByFileList(attendanceFileList: UploadFile[]): Promise<void> {
    return new Promise((resolve, reject) => {
        const promiseList: Promise<void>[] = [];
        for (let i = 0, limit = attendanceFileList.length; i < limit; i++) {
            const file = attendanceFileList[i];
            if (file.originFileObj !== undefined) {
                promiseList.push(parseAttendanceRecordByFile(file));
            }
        }
        Promise.all(promiseList).then(() => {
            refreshIsValidStatus();
            resolve();
        }, reject);
    });
}